#pragma once
#include "formatter.hpp"
#include "message.hpp"
#include "level.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <mutex>
#include <atomic>
#include <cstdarg>
#include <cstdio>
#include <unordered_map>

namespace Log
{
    class Logger
    {
    public:
        using ptr = std::shared_ptr<Logger>;
        Logger(LogLevel::value limit_level, Formatter::ptr formatter, std::vector<LogSink::ptr> &sinks, std::string logger_name)
            : _limit_level(limit_level),
              _formatter(formatter),
              _sinks(sinks),
              _logger_name(logger_name)
        {
        }

        const std::string &getName() { return _logger_name; }

        void debug(const char *file, size_t line, const char *fmt, ...)
        {
            //  判断当前level等级是否大于等于_limit_level
            if (shouldLog(LogLevel::value::DEBUG) == false)
                return;
            //  不定参数
            va_list al;
            va_start(al, fmt);

            logMsgToStr(file, line, fmt, al, LogLevel::value::DEBUG);
            va_end(al);
        }
        void info(const char *file, size_t line, const char *fmt, ...)
        {
            //  fmt 是格式化字符串（format string）的缩写，用于支持可变参数函数，就像 printf 一样。
            //  判断当前level等级是否大于等于_limit_level
            if (shouldLog(LogLevel::value::INFO) == false)
                return;
            //  不定参数
            va_list al;
            va_start(al, fmt);

            logMsgToStr(file, line, fmt, al, LogLevel::value::INFO);
            va_end(al);
        }
        void warn(const char *file, size_t line, const char *fmt, ...)
        {
            //  判断当前level等级是否大于等于_limit_level
            if (shouldLog(LogLevel::value::WARN) == false)
                return;
            //  不定参数
            va_list al;
            va_start(al, fmt);

            logMsgToStr(file, line, fmt, al, LogLevel::value::WARN);
            va_end(al);
        }
        void error(const char *file, size_t line, const char *fmt, ...)
        {
            //  判断当前level等级是否大于等于_limit_level
            if (shouldLog(LogLevel::value::ERROR) == false)
                return;
            //  不定参数
            va_list al;
            va_start(al, fmt);

            logMsgToStr(file, line, fmt, al, LogLevel::value::ERROR);
            va_end(al);
        }
        void fatal(const char *file, size_t line, const char *fmt, ...)
        {
            //  判断当前level等级是否大于等于_limit_level
            if (shouldLog(LogLevel::value::FATAL) == false)
                return;
            //  不定参数
            va_list al;
            va_start(al, fmt);

            logMsgToStr(file, line, fmt, al, LogLevel::value::FATAL);
            va_end(al);
        }

        void setLevel(LogLevel::value level)
        {
            _limit_level.store(level);
        }

        LogLevel::value getLevel() const
        {
            return _limit_level.load();
        }

    protected:
        bool shouldLog(LogLevel::value level)
        {
            return (level >= _limit_level);
        }

        void logMsgToStr(const char *file, size_t line, const char *fmt, va_list &al, LogLevel::value level)
        {
            char *buf;
            int n = vasprintf(&buf, fmt, al);
            if (n < 0)
            {
                std::cerr << "日志消息格式化失败！！\n";
                return;
            }
            //  初始化一个日志消息对象
            LogMsg lm(line, file, _logger_name, buf, level);
            //  将日志消息对象中的信息格式化成一个字符串
            std::string s;
            s = _formatter->format(lm);
            //  将格式化完成的字符串放入到 logsink中
            logSink(s);
        }
        virtual void logSink(const std::string &Msg) = 0;

    protected:
        std::mutex _mutex;                         // 锁
        std::atomic<LogLevel::value> _limit_level; // 限制等级
        Formatter::ptr _formatter;                 // 日志格式化对象
        std::vector<LogSink::ptr> _sinks;          // 日志落地数组
        std::string _logger_name;                  // 日志器名称
    };

    class SyncLogger : public Logger
    {
    public:
        using ptr = std::shared_ptr<SyncLogger>;
        SyncLogger(LogLevel::value limit_level, Formatter::ptr formatter, std::vector<LogSink::ptr> &sinks, std::string logger_name)
            : Logger(limit_level, formatter, sinks, logger_name) // 这 不是创建一个新的 Logger 对象，而是 初始化 SyncLogger 作为 Logger 子类中继承来的那一部分。

        {
            // std::cout << "同步日志器:" << logger_name << "创造成功...\n";
        }

        void logSink(const std::string &Msg) override
        {
            std::unique_lock<std::mutex> lock(_mutex); // 当前业务中只有一个主线程调用是可以不加锁的，但是考虑到未来可能有多个线程调用，所以提前加锁
            if (_sinks.empty())
            {
                std::cerr << "落地数组为空！！\n";
                return;
            }

            for (auto &sn : _sinks)
            {
                sn->log(Msg.c_str(), Msg.size());
            }
        }
    };

    class AsyncLogger : public Logger
    {
    public:
        using ptr = std::shared_ptr<AsyncLogger>;
        AsyncLogger(LogLevel::value limit_level, Formatter::ptr formatter, std::vector<LogSink::ptr> &sinks, std::string logger_name, AsyncSafeType &async_type)
            : Logger(limit_level, formatter, sinks, logger_name), // 这 不是创建一个新的 Logger 对象，而是 初始化 SyncLogger 作为 Logger 子类中继承来的那一部分。
              _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::readLog, this, std::placeholders::_1), async_type))
        {
            // std::cout << "异步日志器:" << logger_name << "创造成功...\n";
        }

        void logSink(const std::string &Msg) override
        {
            _looper->push(Msg.c_str(), Msg.size());
        }

        void readLog(Buffer &buffer)
        {
            if (_sinks.empty())
            {
                std::cerr << "落地数组为空！！\n";
                return;
            }

            for (auto &sn : _sinks)
            {
                sn->log(buffer.begin(), buffer.readAbleSize());
            }
        }

    private:
        AsyncLooper::ptr _looper; // 异步日志处理器
    };

    enum class BuildType
    {
        LOGGER_SYNC,
        LOGGER_ASYNC
    };
    // 日志器建造者类
    class LoggerBuilder
    {
    public:
        using ptr = std::shared_ptr<LoggerBuilder>;
        LoggerBuilder() : _limit_level(LogLevel::value::DEBUG), _logger_type(BuildType::LOGGER_SYNC), _async_type(AsyncSafeType::SAFE) {}
        void buildAsyncUnSafe() { _async_type = AsyncSafeType::UNSAFE; }
        void buildLoggerType(BuildType type) { _logger_type = type; }
        void buildloggerName(std::string logger_name) { _logger_name = logger_name; }
        void buildloggerLevel(LogLevel::value level) { _limit_level = level; }
        void buildloggerFormater(const std::string pattern) { _formatter = std::make_shared<Formatter>(pattern); }
        // void buildloggerFormatter(const Formatter::ptr &formatter) { _formatter = formatter; }

        /*
            关于 const & 指针的理由：
            shared_ptr 本身虽然是轻量封装，但 复制仍涉及引用计数的原子操作。
            如果你传值（Formatter::ptr formatter），那么：
            会多一次引用计数 +1 和 -1 的开销。
            如果你不需要对指针本身做修改（例如 reset），则传引用更合理。
        */
        template <typename SinkType, typename... Args>
        void buildsink(Args &&...args)
        {
            LogSink::ptr sink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(sink);
        }

        virtual Logger::ptr build() = 0;

    protected:
        AsyncSafeType _async_type;        // 异步日志类型
        BuildType _logger_type;           // 日志器种类
        LogLevel::value _limit_level;     // 限制等级
        Formatter::ptr _formatter;        // 日志格式化对象
        std::vector<LogSink::ptr> _sinks; // 日志落地数组
        std::string _logger_name;         // 日志器名称
    };

    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        using ptr = std::shared_ptr<LocalLoggerBuilder>;
        Logger::ptr build() override
        {
            // 如果日志器名字为空
            if (_logger_name.empty())
            {
                std::cerr << "日志器名字不能为空！！！\n";
                abort();
            }

            if (_formatter.get() == nullptr)
            {
                // std::cout << "当前日志器：" << _logger_name << " 未检测到日志格式,设置默认设置\n";
                _formatter = std::make_shared<Formatter>();
            }

            if (_sinks.empty())
            {
                // std::cout << "当前日志器：" << _logger_name << " 未检测到落地方向，默认设置为标准输出!\n";
                _sinks.push_back(std::make_shared<StdOutSink>());
            }

            Logger::ptr lg;
            if (_logger_type == BuildType::LOGGER_SYNC)
            {
                lg = std::make_shared<SyncLogger>(_limit_level, _formatter, _sinks, _logger_name);
            }
            else
            {
                lg = std::make_shared<AsyncLogger>(_limit_level, _formatter, _sinks, _logger_name, _async_type);
            }

            return lg;
        }
    };

    // 局部日志管理器
    class LoggerManager
    {
    public:
        static LoggerManager &getInstance()
        {
            // 在c++11之后，针对静态局部变量，编译器在编译的层面实现了线程安全
            // 当静态局部变量在没有构造完全之前，其它的线程进入就会阻塞
            static LoggerManager lm;
            return lm;
        }

        // 禁止拷贝和赋值
        LoggerManager(const LoggerManager &) = delete;
        LoggerManager &operator=(const LoggerManager &) = delete;

        void addLogger(const std::string &name, const Log::Logger::ptr new_logger)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(name, new_logger));
        }

        bool hasLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return false;
            }
            return true;
        }

        Logger::ptr getLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
            {
                return Logger::ptr();
            }
            return it->second;
        }

        // 若返回的是引用，指向内部 _default_logger 的真实对象。这意味着调用方可以修改它的指针本身
        Logger::ptr getDefaultLogger()
        {
            std::unique_lock<std::mutex> lock(_mutex);
            return _default_logger;
        }

        void setGlobalLogLevel(LogLevel::value level)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            for (auto &kv : _loggers)
            {
                kv.second->setLevel(level); // 因为是 atomic
            }
        }

        void setDefaultLoggerLevel(LogLevel::value level)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_default_logger)
            {
                _default_logger->setLevel(level);
            }
        }

    private:
        LoggerManager()
        {
            // 这里一定要是LocalBuilder 否则会陷入循环卡死，因为下面会调用build()
            std::shared_ptr<LocalLoggerBuilder> builder(new LocalLoggerBuilder());
            builder->buildloggerName("default");
            _default_logger = builder->build();
            _loggers.insert(std::make_pair("default", _default_logger));
        }

        ~LoggerManager() = default;

    private:
        std::mutex _mutex;
        std::unordered_map<std::string, Logger::ptr> _loggers; // 管理日志器map
        Logger::ptr _default_logger;                           // 默认日志器
    };

    // 全局日志建造器
    class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        using ptr = std::shared_ptr<GlobalLoggerBuilder>;
        Logger::ptr build() override
        {
            // 如果日志器名字为空
            if (_logger_name.empty())
            {
                std::cerr << "日志器名字不能为空！！！\n";
                abort();
            }

            if (_formatter.get() == nullptr)
            {
                // std::cout << "当前日志器：" << _logger_name << " 未检测到日志格式,设置默认设置\n";
                _formatter = std::make_shared<Formatter>();
            }

            if (_sinks.empty())
            {
                // std::cout << "当前日志器：" << _logger_name << " 未检测到落地方向，默认设置为标准输出!\n";
                _sinks.push_back(std::make_shared<StdOutSink>());
            }

            Logger::ptr lg;
            if (_logger_type == BuildType::LOGGER_SYNC)
            {
                lg = std::make_shared<SyncLogger>(_limit_level, _formatter, _sinks, _logger_name);
            }
            else
            {
                lg = std::make_shared<AsyncLogger>(_limit_level, _formatter, _sinks, _logger_name, _async_type);
            }

            LoggerManager::getInstance().addLogger(_logger_name, lg);
            return lg;
        }
    };
}